package com.jian.mygame;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Random;

import org.jbox2d.collision.PolygonShape;
import org.jbox2d.collision.ShapeType;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.contacts.ContactPoint;

import com.jian.mygame.MultiTouchHandler.MultiTouchEvent;
import com.jian.mygame.MultiTouchHandler.MyTouchEvent;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.SystemClock;
import android.text.format.Time;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;

class GameHandler extends Object {
    static GameObjectCollection mGameObjectCollection = null;
    //static MyWorld mWorld = null;

    /** The drawable to use as the background of the animation canvas */
    private Bitmap mBackgroundImage;
    
    /**
     * Current height of the surface/canvas.
     */
    private int mCanvasHeight = 1;

    /**
     * Current width of the surface/canvas.
     */
    private int mCanvasWidth = 1;
    
    private int m_Interval;
    
    private int mScore;
    
    //private float mLeftGunPosX = 80;
    //private float mLeftGunPosY = 250;
    //private float mRightGunPosX = 450;
    //private float mRightGunPosY = 250;
        
    private Long mGameTime = 0L;
    private Long mLastTime = 0L;
    
    private boolean mGameStarted = false;
    
    private MultiTouchHandler mMultiTouchHandler;
    private MyToolBox mToolBox;
    
	public GameHandler(Context context){
        Resources res = context.getResources();
      
        // Create Box2D World
        //mWorld = new MyWorld();
        //mWorld.CreateWorld(context);
        mScore = 0;
        updateLastTime();

        //Create GameObjectCollection
        mGameObjectCollection = new GameObjectCollection(context); 
        
        //Initialize MultiTouchHandler
        mMultiTouchHandler = new MultiTouchHandler();
        
        mToolBox = new MyToolBox(context, this);
        
        // load background image as a Bitmap instead of a Drawable b/c
        // we don't need to transform it and it's faster to draw this way
        mBackgroundImage = BitmapFactory.decodeResource(res, R.drawable.gam_bg);

        MySound.loadSound(context);
	}
	
	public void resizeBackGroundImg(int CanvasWidth, int CanvasHeight){
        mCanvasWidth = CanvasWidth;
        mCanvasHeight = CanvasHeight;
        mBackgroundImage = Bitmap.createScaledBitmap(
                mBackgroundImage, CanvasWidth, CanvasHeight, true);
	}
		
	
	public void updateLastTime() {
		mLastTime = SystemClock.uptimeMillis();
	}
	
	public void updateGame(Canvas canvas){
		try {
			//if( !mIsGameEnd ) {

		        // Draw the background image. Operations on the Canvas accumulate
		        // so this is like clearing the screen.
		    	drawBackGroud(canvas);
				//canvas.drawBitmap(mBackgroundImage, 0, 0, null);
	    	
				//update all game objects
		    	mGameObjectCollection.updateWorld();
		    	
		    	//Generate new object in the world
	//	        if ( m_Interval >= 200 ){
	//	        	Random rnd = new Random();
	//		        int num = rnd.nextInt(100);
	//	        	mWorld.addNewBird(num);
	//	        	m_Interval = 0;
	//	        } else {
	//	        	m_Interval++;
	//	        }
				
		        
				//Draw All Contact Point
		    	mGameObjectCollection.updateContact(canvas);
		
				//Draw all Objects in MyWorld
		    	updateAllObjects(canvas);
								
				//Draw score
				drawScore(canvas);
				
				//Draw game time
				drawTime(canvas);
				
				//Draw Tools
				mToolBox.drawTools(canvas);
				
				//
				checkGameEnd(canvas);
			//} 
			
		} catch( Exception e) {
			Log.e("Exception", "Exception! " + e.getMessage());
			Log.e("Exception", "---Call Stack---\n");
			for( StackTraceElement ste : e.getStackTrace()) {
				Log.e("Exception", " " + ste.getClassName() + "." + ste.getMethodName()
						               + "(" + ste.getLineNumber() + ")\n");
			}
			//throw e;
		} finally {
			//Nothing need to be done
		}
	}

	protected void updateAllObjects(Canvas canvas){
		MyAnimation anima = null;
		ShapeType type = null;
		GameObject gameobj = null;
		Iterator<GameObject> it = mGameObjectCollection.getGameObjectIterator();
		
		//for (Body body = mWorld.getBodyList(); body != null; body = body.getNext()) {
		while(it.hasNext()) {
			gameobj = it.next();
			
			Body body = gameobj.getBody();
			BodyExtend bodyextend = gameobj.getBodyExtend(); //(BodyExtend)body.getUserData();
			Boolean isDestroyed = false;
			
			//Draw all elements which need to draw on screen
			if( bodyextend != null ) {
				if( bodyextend.isDrawable() ) {
					
					mTargetCnt = 0;
					if( bodyextend.getRole() == BodyExtend.ROLE_TARGET ) {
						mTargetCnt++;
					}
					
					if( (bodyextend.getRole() == BodyExtend.ROLE_TARGET ||
						 bodyextend.getRole() == BodyExtend.ROLE_TOOL ||
						 bodyextend.getRole() == BodyExtend.ROLE_BULLET )
						&& false == TestInBoarder(body) ) {
						mScore += bodyextend.getScore();
						mGameObjectCollection.destroy(gameobj);
						//mWorld.destroyBody(body);
						isDestroyed = true;
					} else {
					
						//if(/*!body.isSleeping() ||*/ ( bodyextend.getRole() == BodyExtend.ROLE_TOOL )){
						type = body.getShapeList().getType();
	        			switch(type){
	        			case CIRCLE_SHAPE:
	        				MyPainter.drawCircle(canvas, 
	        						body.getPosition().x*MyWorld.RATE, 
	        						body.getPosition().y*MyWorld.RATE,
	        						body.getShapeList().getSweepRadius()*MyWorld.RATE,
	        						body.getAngle(),
	        						bodyextend.getColor(),
	        						bodyextend.getImage());
	        				break;
	        			case POLYGON_SHAPE:
	        				Drawable image = ((BodyExtend)(body.getUserData())).getImage();
	        				
	        				if( image == null){
	        					MyPainter.drawPolygon(canvas, 
	        							body.getPosition().x, 
		        						body.getPosition().y,
		    						    ((PolygonShape) body.getShapeList()).getVertices(),
		        	    			    body.getAngle(),
		        	    			    bodyextend.getColor());
	        							
//	        					drawBox(canvas, 
//		        						body.getPosition().x*MyWorld.RATE, 
//		        						body.getPosition().y*MyWorld.RATE,
//		    						    ((PolygonShape) body.getShapeList()).getVertices()[0].abs().x*MyWorld.RATE ,
//		        	    			    ((PolygonShape) body.getShapeList()).getVertices()[0].abs().y*MyWorld.RATE ,
//		        	    			    body.getAngle(),
//		        	    			    bodyextend.getColor());
	        				} else {
	            				MyPainter.drawBox(canvas, 
	            						body.getPosition().x*MyWorld.RATE, 
	            						body.getPosition().y*MyWorld.RATE,
	            						body.getAngle(),
	            						bodyextend.getImage());
	        				}
	        				break;
	        			default:
	        				break;
	        			}
	        			//}
					
					}
				} // if isDrawable()
	
				//Draw Dying Animation for each body
				if( !isDestroyed ) {
					if( bodyextend.getRole() != BodyExtend.ROLE_STATIC && bodyextend.getLife() <= 0 ) {
		    			anima = bodyextend.getAnimation();
		    			if( null != anima ) {
		    				anima.updateTimer();
		    				boolean bRet = anima.onDraw( canvas );
		    				if(!body.isSleeping()){
		    					body.putToSleep();
		    					bodyextend.setDrawable(false);
		    				}
		    				if( !bRet ) {
		    					mGameObjectCollection.destroy(gameobj);
		    					//mWorld.destroyBody(body);
		    				}
		    			} else {
		    				mGameObjectCollection.destroy(gameobj);
		    				//mWorld.destroyBody(body);
		    			}
					}
				}
			} else { // If !Null
				//TBD: All body I set must have BodyExtend, not sure what this body is.
				//I guess this is used in Box2D inside. Ignore it temporarily.
				
				//Log.e("GameHandler", "Null! "+ body.toString() );
				//Log.e("GameHandler", "Null! "+ body.toString() + " / Type: " + body.getShapeList().getType().toString()
				//	   + " / Friction:" + body.getShapeList().getFriction() );
			}
		}//End For
	}
	
	private int mTargetCnt = 4;
	private boolean mIsGameEnd = false;
	private void checkGameEnd( Canvas canvas ){
		
		if( mTargetCnt <= 0 ) {
			String str = null;
			Paint mPaint = new Paint();
			
			mIsGameEnd = true;
			if( mScore == 0 ) {
				//GameOver
				str = "Game Over!";
				mPaint.setColor(Color.RED);
			} else {
				//Pass
				str = "You Win!";
				mPaint.setColor(Color.GREEN);
			}
		
			//canvas.drawText(str, (mBoarderLeft+mBoarderRight)/2, (mBoarderTop+mBoarderBottom)/2, mPaint);
		}
		
	}

	private void drawBackGroud(Canvas canvas) {
		Paint mPaint = new Paint();
		
		//Top Bar
		//mPaint.setColor(Color.BLACK);
		//canvas.drawRect( 0, 0, mBoarderRight, mBoarderTop, mPaint);
		canvas.drawColor(Color.BLACK);
		
		mPaint.setColor(Color.argb(0xCC, 255, 255, 255));
		canvas.drawRect( mBoarderLeft+mBoarderWidth, mBoarderTop+mBoarderWidth, 
				        mBoarderRight-mBoarderWidth, mBoarderBottom-mBoarderWidth, mPaint);
	}
	

	private void drawScore(Canvas canvas){
		MyPainter.drawText(canvas, 20, 30, Color.BLUE, Color.TRANSPARENT, String.valueOf(mScore));
//		//Save Current Canvas
//		canvas.save();
//		
//		Paint mPaint = new Paint();
//		mPaint.setAntiAlias(true);
//		mPaint.setTextSize(24);
//		mPaint.setColor(Color.BLUE);
//		canvas.drawText(String.valueOf(mScore), 20, 30, mPaint);
//		
//		//Restore for the next object to be drawn
//		canvas.restore();
	}
		
	private void drawTime(Canvas canvas){
		//Time passtime = new Time();
		//passtime.set(SystemClock.uptimeMillis()-mStartTime);
		Long passtime = SystemClock.uptimeMillis()-mLastTime;
		mLastTime = SystemClock.uptimeMillis();
		passtime = mGameTime + passtime;
		mGameTime = passtime;
		Long passtime_mil = passtime%1000;
		passtime /= 1000;
		Long passtime_sec = (passtime)%60;
		passtime /= 60;
		long passtime_min = (passtime)%60;
		passtime /= 60;
		long passtime_hour = passtime;
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss SSS");
		//Log.v("Test", simpleDateFormat.format(date))
		
		MyPainter.drawText(canvas, 120, 30, Color.BLUE, Color.TRANSPARENT, 
				        String.valueOf(passtime_hour) + ":" + 
				        String.valueOf(passtime_min) + ":" + 
				        String.valueOf(passtime_sec) );

//		//Save Current Canvas
//		canvas.save();
//		
//		Paint mPaint = new Paint();
//		mPaint.setAntiAlias(true);
//		mPaint.setTextSize(24);
//		mPaint.setColor(Color.BLUE);
//		canvas.drawText(String.valueOf(passtime_hour) + ":" + 
//				        String.valueOf(passtime_min) + ":" + 
//				        String.valueOf(passtime_sec) /*+ ":" +
//				        String.valueOf(passtime_mil)*/, 120, 30, mPaint);
//		
//		//Restore for the next object to be drawn
//		canvas.restore();
	}
	
    public boolean doTouchEvent( MotionEvent event) {
    	boolean bhandled = false;
    	
    	try {
			MultiTouchEvent mtv = mMultiTouchHandler.onTouchEvent(event);

			bhandled = mToolBox.onTouchEvent(mtv);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			Log.e("Exception", "Exception! " + e.getMessage());
			Log.e("Exception", "---Call Stack---\n");
			for( StackTraceElement ste : e.getStackTrace()) {
				Log.e("Exception", " " + ste.getClassName() + "." + ste.getMethodName()
						               + "(" + ste.getLineNumber() + ")\n");
			}
		}
    	
    	return bhandled;
    }
    
//    public void changeDirection( MyWorld.WorldDirection dir ) {
//    	mWorld.setGravity(dir);
//    }
    
    public void changeDirection( float x, float y) {
    	mGameObjectCollection.setGravity( x, y );
    }
 
    //Create Objects
	private static float mBoarderWidth = 5.0f;
	private static float mBoarderLeft = 0.0f;
	private float mBoarderRight = 0.0f;
	private float mBoarderTop = 0.0f;
	private float mBoarderBottom = 0.0f;
	
	public void createGameObjects(){
        if( !mGameStarted ) {
			CreateBoarder(mCanvasWidth,mCanvasHeight);
	        //CreateTargetObjects(mTargetCnt);
	        //CreateBulletObjects(8);
			mGameObjectCollection.TestCreatePolygon();
	        mGameStarted = true;
        }
	}
	
//	public void CreateTargetObjects( int ObjectNum ) {
//		Random rnd = new Random();
//		
//		for( int i=0; i<ObjectNum; i++ ) {
//			int size = MyFactory.mTargetRes.length;
//			int type = rnd.nextInt(100)%size;
//	        float x = rnd.nextInt(mCanvasWidth/2);
//	        float y = rnd.nextInt(mCanvasHeight);
//	        x = Math.max(mBoarderLeft+mBoarderWidth, x );
//	        x = Math.min(mBoarderRight-mBoarderWidth, x);
//	        y = Math.max(mBoarderTop+mBoarderWidth, y);
//	        y = Math.min(mBoarderBottom-mBoarderWidth, y);
//	        
//	        mWorld.createBody(x, y, 0.0f, MyFactory.mTargetRes[type], null, BodyExtend.ROLE_TARGET, false );
//		}
//	}
//
//	public void CreateBulletObjects( int ObjectNum ) {
//		Random rnd = new Random();
//		Body body = null;
//		
//		for( int i=0; i<ObjectNum; i++ ) {
//			int size = MyFactory.mBulletRes.length;
//			int type = rnd.nextInt(100)%size;
//	        float x = mCanvasWidth/2+rnd.nextInt(mCanvasWidth/2);
//	        float y = rnd.nextInt(mCanvasHeight);
//	        x = Math.max(mBoarderLeft+mBoarderWidth, x );
//	        x = Math.min(mBoarderRight-mBoarderWidth, x);
//	        y = Math.max(mBoarderTop+mBoarderWidth, y);
//	        y = Math.min(mBoarderBottom-mBoarderWidth, y);
//	        
//	        body = mWorld.createBody(x, y, 0.0f, MyFactory.mBulletRes[type], MyFactory.mAnimationRes[0], BodyExtend.ROLE_BULLET, false );
//		}
//	}
	
	public void CreateBoarder(int CanvasWidth, int CanvasHeight) {
	    float xHoleTopLeft = 0.0f;
	    float yHoleTopLeft = 0.0f;
	    float HeightHole = 0.0f;
	    	
        mCanvasWidth = CanvasWidth;
        mCanvasHeight = CanvasHeight;
        mBoarderTop = CanvasHeight / 8;
        mBoarderBottom = CanvasHeight;
        mBoarderRight = CanvasWidth;
        xHoleTopLeft = mBoarderRight-mBoarderWidth;
        yHoleTopLeft = mBoarderTop + CanvasHeight / 8;
        HeightHole = CanvasHeight/5;        
        
	    //Create Border
	    //Top
	    mGameObjectCollection.createSimpleBox(mBoarderLeft, mBoarderTop, CanvasWidth, 
	    		               mBoarderWidth, 
	    		               Color.GREEN, true, true, BodyExtend.ROLE_STATIC);
	    //Bottom
	    mGameObjectCollection.createSimpleBox(mBoarderLeft, mBoarderBottom-mBoarderWidth, 
	    		               CanvasWidth, mBoarderWidth, 
	    		               Color.GREEN, true, true, BodyExtend.ROLE_STATIC);
	    //Left
	    mGameObjectCollection.createSimpleBox(mBoarderLeft, mBoarderTop, mBoarderWidth, 
	    		               CanvasHeight, Color.GREEN, true, true, BodyExtend.ROLE_STATIC);
	    //Right
	    mGameObjectCollection.createSimpleBox(mBoarderRight-mBoarderWidth, mBoarderTop, 
	    		               mBoarderWidth, yHoleTopLeft - mBoarderTop, 
	    		               Color.GREEN, true, true, BodyExtend.ROLE_STATIC);
	    mGameObjectCollection.createSimpleBox(mBoarderRight-mBoarderWidth, yHoleTopLeft+HeightHole, 
	    		               mBoarderWidth, mBoarderBottom-(yHoleTopLeft+HeightHole), 
	    		               Color.GREEN, true, true, BodyExtend.ROLE_STATIC);
	    
	    //createBox(180f, 200f, R.drawable.icon, Color.MAGENTA, true);
	    //createBox(100f, 200f, R.drawable.icon, Color.LTGRAY, false);  
	    //createBox(160f, 150f, 160f, 10f, Color.CYAN, false);
	    //createCircle(160, 200, 30f, Color.GRAY);
	    //createCircle(160, 100, 10f, Color.GREEN);
	    //createCircle(120, 40, 20f, Color.RED);
	    
	    //loadTools();
	}
	
	public boolean TestInBoarder( Body body ) {
		boolean ret = true;
		BodyExtend bodyextend = (BodyExtend)body.getUserData();
		
		//out of Right boarder
		if( mBoarderRight < body.getPosition().x*MyWorld.RATE - bodyextend.getImage().getIntrinsicWidth() ) {
			return false;
		}
		//Out of Left Boarder
		if( mBoarderLeft > body.getPosition().x*MyWorld.RATE + bodyextend.getImage().getIntrinsicWidth() ) {
			return false;
		}
		//Out of Top Boarder
		if( mBoarderTop > body.getPosition().y*MyWorld.RATE + bodyextend.getImage().getIntrinsicHeight() ) {
			return false;
		}
		//Out of Bottom Boarder
		if( mBoarderBottom < body.getPosition().y*MyWorld.RATE - bodyextend.getImage().getIntrinsicHeight() ) {
			return false;
		}
		
		return ret;
	}
	
	public void AddPolygonObject( Vec2 vec[]) {
		mGameObjectCollection.CreatePolygon(vec);
	}
	
}